package com.tianquan.redisCache;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Objects;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.redisCache
 * @Author: tianquan
 * @CreateTime: 2024-10-09 15:30
 * @Description: 自定义缓存实现
 * @Version: 1.1
 */
@Aspect
@Component
public class CacheAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.tianquan.redisCache.Cache)")
    public void cachePointcut() {
    }

    @Around("cachePointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Cache cache = method.getAnnotation(Cache.class);

        // 解析缓存Key
        String key = parseKey(cache.key(), method, joinPoint.getArgs());
        String fullKey = cache.prefix() + ":" + key;

        // 查询缓存
        RBucket<Object> bucket = redissonClient.getBucket(fullKey);
        Object cachedValue = bucket.get();
        if (cachedValue != null) {
            logInfo("Cache hit for key: " + fullKey);
            return cachedValue;
        }

        // 执行目标方法并获取结果
        Object result;
        try {
            result = joinPoint.proceed(joinPoint.getArgs());
        } catch (Throwable e) {
            logError("Error executing target method: " + method.getName(), e);
            throw e;
        }

        // 写入缓存
        if (cache.isExpire()) {
            bucket.set(result, cache.time(), cache.unit());
        } else {
            bucket.set(result);
        }
        logInfo("Cache set for key: " + fullKey);

        return result;
    }

    /**
     * 解析Key，支持参数和对象属性
     */
    private String parseKey(String key, Method method, Object[] args) throws Exception {
        if (key == null || !key.contains("#")) {
            // 不需要解析
            return key;
        }

        key = key.replace("#", "");
        Parameter[] parameters = method.getParameters();

        if (key.contains(".")) {
            String[] parts = key.split("\\.");
            if (parts.length != 2) {
                throw new IllegalArgumentException("Invalid key format: " + key);
            }
            String paramName = parts[0];
            String fieldName = parts[1];

            Object param = getParamByName(parameters, args, paramName);
            if (param == null) {
                throw new IllegalArgumentException("Parameter not found: " + paramName);
            }

            return getFieldValue(param, fieldName);
        }

        return getParamValueByName(parameters, args, key);
    }

    /**
     * 根据参数名称获取值
     */
    private String getParamValueByName(Parameter[] parameters, Object[] args, String name) {
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].getName().equals(name)) {
                return Objects.toString(args[i], "");
            }
        }
        throw new IllegalArgumentException("Parameter not found: " + name);
    }

    /**
     * 根据参数名称获取参数对象
     */
    private Object getParamByName(Parameter[] parameters, Object[] args, String name) {
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].getName().equals(name)) {
                return args[i];
            }
        }
        return null;
    }

    /**
     * 获取对象的字段值
     */
    private String getFieldValue(Object object, String fieldName) throws Exception {
        Method getter = object.getClass().getMethod("get" + capitalize(fieldName));
        Object value = getter.invoke(object);
        return Objects.toString(value, "");
    }

    /**
     * 首字母大写
     */
    private String capitalize(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    private void logInfo(String message) {
        System.out.println("[INFO] " + message);
    }

    private void logError(String message, Throwable throwable) {
        System.err.println("[ERROR] " + message);
        throwable.printStackTrace();
    }
}
